#include "stdafx.h"
#include "Console.h"
#include "Console.Commands.h"
#include "SettingsManager.h"
#include "..\EdgeGraphics\HUD.h"
#include "..\EdgeMath\VectorHelper.h"
#include "..\EdgeControls\Input.h"
#include "..\EdgeGraphics\Fonts.h"
#include "..\EdgeGraphics\BitmapFont.h"
#include "..\EdgeGraphics\BlendStateManager.h"

Console::Console(void)
{
	commands["SHUTDOWN"].subscribers.push_back(Functor<console_event>(&quit_game, 0));
	commands["SHOWCAMPOS"].subscribers.push_back(Functor<console_event>(&showCamPos, 0));
	commands["BEGINNETWORKGAME"].Subscribe(Functor<console_event>(&beginNetworkGame, 0));
	buffer_info.push_back({ "", VectorHelper::vector_4::white });
	sameKeyTimer = keyTimerReset;
}

Console::~Console(void)
{
}

void Console::WriteLine(const char* line, Vector4& color)
{
	line_info l;
	l.color = color;
	l.line = line;
	buffer_info.insert(buffer_info.begin(), l);
}

void Console::SubscribeToString(const char* name, console_event callback)
{
	commands[name].subscribers.push_back(Functor<console_event>(callback, 0));
}

/*static*/ Console* Console::GetInstance(void)
{
	static Console instance;

	return &instance;
}

void Console::Show(void)
{
	visible = true;
}

void Console::Hide(void)
{
	visible = false;
}

// break a string into pieces to seperate the function call from its arguments
vector<string> ParseCommand(string& command, const char* delimiter)
{
	vector<string> total;
	string current;
	// find the length of the delimiter
	int num_delims = strlen(delimiter);
	// iterate over the command string
	for (unsigned int i = 0; i < command.size(); i++)
	{
		// store a bool to indicate if this is a delimiter character and should not be added to 'current'
		bool skip = false;
		// iterate over the delimiters
		for (int ii = 0; ii < num_delims; ii++)
		{
			// if this character is a delimeter
			if (delimiter[ii] == command[i])
			{
				// check to see if the current piece is not empty
				if (current.size() > 0)
				{
					total.push_back(current);
					current.clear();
				}
				// signal we found a delimiter character
				skip = true;
				break;
			}
		}

		if (!skip)
			// add the current character to current if it's not a delimiter character
			current.push_back(command[i]);
		else
			// reset skip for next characters in the command
			skip = true;
	}

	if (total.size() == 0)
		total.push_back(command);

	return total;
}

void Console::Update(float dt)
{
#if 0
	Input* pInput = Input::GetInstance();
	static wchar_t char_prev = L'\0';
	char c = pInput->GetAnyKeyDown();
	// if there is a character sitting in the input buffer, and it's not being held down...
	// .. oh yea, also fuck the left mouse button (\x1)
	if (c && c != char_prev && c != '\x1' && c != char(-64))
	{
		/*===================================================<AUTHORS NOTE>===================================================================*/
		/*                                                                                                                                    */
		/*       size checks occour inside 'if' checks to prevent falling to the final 'else' case, causeing new lines						  */
		/*       and backspace characters to be inserted into the new line																	  */
		/*                                                                                                                                    */
		/*====================================================================================================================================*/
		if (c == '\r')
		{
			if (buffer_info[0].line.size() == 0)
			{
				char_prev = c;
				return;
			}
			char delim[] = { '(', ')', ',', ' ', '\0' };
			vector<string> command = ParseCommand(buffer_info[0].line, delim);
			if (command.size() == 0)
			{
				WriteLine("Failed to parse command", VectorHelper::vector_4::red);
				char_prev = c;
				return;
			}
			string command_name = command[0];
			command.erase(command.begin());
			vector<string>* prams = new vector<string>;
			(*prams) = command;
			bool found_command = false;
			for (auto i = commands.begin(); i != commands.end(); i++)
				if (i->first == command_name)
				{
					i->second(nullptr);
					found_command = true;
				}
			if (!found_command)
				WriteLine("Command not found", VectorHelper::vector_4::red);
			delete prams;
			buffer_info.insert(buffer_info.begin(), { "", VectorHelper::vector_4::white });

		}
		else if (c == '\b')
		{
			if (buffer_info[0].line.size() == 0)
			{
				// update previous character
				char_prev = c;
				return;
			}
			// delete the last character on the current line
			buffer_info[0].line.pop_back();
		}
		else
			buffer_info[0].line.push_back(c);
	}
	char_prev = c;
	
	// toggle visible with tilde key
	if (pInput->isKeyPressed(Keys::OEM_TILDE))
		visible = !visible;
#endif
}

void Console::Draw(void)
{
	if (!visible)
		return;
	BlendStateManager::GetInstance()->SetBlendState(BlendStateManager::GetInstance()->blendStates.alphaBlend);

	Hud* pHud = Hud::GetInstance();
	GraphicsManager* pGraphics = GraphicsManager::GetInstance();
	int scr_height = SettingsManager::GetInstance()->getSetting("ScreenHeight")._int;
	pHud->DrawRectangle(0, 0, SettingsManager::GetInstance()->getSetting("ScreenWidth")._int, scr_height, VectorHelper::vector_4::blue);
	
	pGraphics->ClearDepthBuffer(1.f);
	BitmapFont* arial = Fonts::GetInstance()->arial;
	for (unsigned int i = 0; i < buffer_info.size(); i++)
	{
		arial->Draw(buffer_info[i].line.c_str(), 10, scr_height - 50 - (i * 50), 1.f, buffer_info[i].color);
	}
	BlendStateManager::GetInstance()->SetBlendState(BlendStateManager::GetInstance()->blendStates.opaque);
}